package org.example.httpproxy;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.handler.codec.http.*;

/**
 * @author 刁海文
 * @date 2022/5/3 19:00
 */
public record ChannelListener(
        Channel clientChannel,
        Channel remoteChannel,
        boolean isConnectMethod,
        FullHttpRequest request
        , HttpProxyClientHandler handler
) implements ChannelFutureListener {

    @Override
    public void operationComplete(ChannelFuture future) {
        if (future.isSuccess()) {
            // connection is ready, enable AutoRead
            clientChannel.config().setAutoRead(true);

            if (isConnectMethod) {
                // CONNECT 请求回复连接建立成功
                HttpResponse connectedResponse = new DefaultHttpResponse(request.protocolVersion(), new HttpResponseStatus(200, "Connection Established"));
                clientChannel.writeAndFlush(connectedResponse);
            } else {
                // 普通http请求解析了第一个完整请求，第一个请求也要原样发送到远端服务器
                remoteChannel.writeAndFlush(request);
            }
            // 第一个完整Http请求处理完毕后，不需要解析任何 Http 数据了，直接盲目转发 TCP 流就行了
            // 所以无论是连接客户端的 clientChannel 还是连接远端主机的 remoteChannel 都只需要一个 RelayHandler 就行了。
            // 代理服务器在中间做转发。
            // 客户端   --->  clientChannel --->  代理 ---> remoteChannel ---> 远端主机
            // 远端主机 --->  remoteChannel  --->  代理 ---> clientChannel ---> 客户端
            clientChannel.pipeline().remove(HttpRequestDecoder.class);
            clientChannel.pipeline().remove(HttpResponseEncoder.class);
            clientChannel.pipeline().remove(HttpObjectAggregator.class);
//            clientChannel.pipeline().remove(HttpProxyClientHandler.class);
            clientChannel.pipeline().remove(handler);
            clientChannel.pipeline().addLast(new RelayHandler(remoteChannel));

            remoteChannel.pipeline().remove(HttpRequestEncoder.class);
            remoteChannel.pipeline().addLast(new RelayHandler(clientChannel));
        } else {
            clientChannel.close();
        }
    }
}
